package edu.iupui.csci.mortgageplanner.util;

import java.util.ArrayList;
import java.util.List;

public class Mortgage {
	
	double propertyValue;
	double downpayment;
	double interestRate;
	double mortgageTerm;
	
	private static Mortgage m;
	
	private static List<MortgagePeriodDetails> mDetails = null;
	
	public static Mortgage getMortgage() {
		return m;
	}
	
	public static Mortgage getMortgage(double propertyValue, double downpayment, double interestRate, double mortgageTerm) {
		m = new Mortgage(propertyValue, downpayment, interestRate, mortgageTerm);
		return m;
	}

	private Mortgage(double propertyValue, double downpayment, double interestRate, double mortgageTerm) {
		this.propertyValue = propertyValue;
		this.downpayment = downpayment;
		this.interestRate = interestRate;
		this.mortgageTerm = mortgageTerm;
	}
	
	public double getMonthlyPayment() {
		double monthlyPayment = 1.0;
		
		double loanAmount = propertyValue - downpayment;
		double monthlyInterestRate  = interestRate/(12 * 100);
		
		monthlyPayment = (loanAmount * monthlyInterestRate) / (1- 1/Math.pow(1 + monthlyInterestRate, mortgageTerm * 12));
		
		return monthlyPayment;
	}
	
	public double getMonthlyTaxes() {
		return propertyValue * 0.7/(12 * 100); 
	}
	
	public double getMonthlyInsurance() {
		return propertyValue * 0.55 / (12 * 100);
	}
	
	/**
	 * http://www.anytimeestimate.com/FHA/fha-mortgage-insurance-calculator.htm
	 * @return
	 */
	public double getMonthlyPMI() {
		double annualPMIFactor = 1.0;
		
		if(mortgageTerm >= 15) {
			annualPMIFactor = 1.4;
		} else {
			annualPMIFactor = 0.7;
		}
		return propertyValue * annualPMIFactor / (12 * 100);
	}
	
	public double getTotalInterest() {
		return ((getMonthlyPayment() * mortgageTerm * 12) - propertyValue + downpayment);
	}
	
	public double getTotalAmount() {
		return ((getMonthlyPayment() * mortgageTerm * 12 + getMonthlyTaxes() * mortgageTerm * 12) + (getMonthlyInsurance() * mortgageTerm * 12));
	}
	
	public List<MortgagePeriodDetails> getMortgageDetails() {
		if (mDetails == null) {
			calculateMortgageDetails();
		}
		return mDetails;
	}
	
	public synchronized void calculateMortgageDetails() {
		mDetails = new ArrayList<MortgagePeriodDetails>();
		
		double remainingPrincipal = propertyValue - downpayment;
		double totalInterest = 0;
		double totalPrincipal = downpayment;
		
		for(int i=0; i< mortgageTerm * 12 && remainingPrincipal > 0; i ++) {
			MortgagePeriodDetails details = new MortgagePeriodDetails(i);
			double periodInterest = remainingPrincipal * interestRate / (12*100);
			double periodPrincipal = getMonthlyPayment() - periodInterest;
			
			remainingPrincipal = remainingPrincipal - periodPrincipal;
			totalInterest = totalInterest + periodInterest;
			totalPrincipal = totalPrincipal + periodPrincipal;
			
			details.setInterest(periodInterest);
			details.setPrincipal(periodPrincipal);
			details.setAdditionalPayment(0);
			
			details.setTaxes(getMonthlyTaxes());
			details.setPmi(getMonthlyPMI());
			details.setInsurance(getMonthlyInsurance());
			
			details.setRemainingPrincipal(remainingPrincipal);
			details.setTotalPrincipal(totalPrincipal);
			details.setTotalInterest(totalInterest);
			mDetails.add(details);
			//System.err.println(remainingPrincipal);
		}
	}
	
	public synchronized void recalculateMortgageDetails(int periodId, double additionalPayment) {
		List<MortgagePeriodDetails> periodList = getMortgageDetails();
		
		MortgagePeriodDetails period = periodList.get(periodId);
		period.setAdditionalPayment(additionalPayment);
		
		double remainingPrincipal = period.getRemainingPrincipal() - additionalPayment;
		double totalInterest = period.getTotalInterest();
		double totalPrincipal = period.getTotalPrincipal() + additionalPayment;
		period.setTotalPrincipal(totalPrincipal);
		period.setRemainingPrincipal(remainingPrincipal);
		
		int i = periodId + 1;
		
		for(; remainingPrincipal > 0 && i < (mortgageTerm * 12); i++) {
			
			if(periodList.size() <= i) {
				MortgagePeriodDetails temp = new MortgagePeriodDetails(i);
				temp.setAdditionalPayment(0);
				periodList.add(temp);
			}
			
			MortgagePeriodDetails details = periodList.get(i);
			double periodInterest = remainingPrincipal * interestRate / (12*100);
			double periodPrincipal = getMonthlyPayment() - periodInterest;
			
			remainingPrincipal = remainingPrincipal - periodPrincipal - details.getAdditionalPayment();
			totalPrincipal = totalPrincipal + periodPrincipal + details.getAdditionalPayment();
			totalInterest = totalInterest + periodInterest;
			
			details.setInterest(periodInterest);
			details.setPrincipal(periodPrincipal);
			
			details.setRemainingPrincipal(remainingPrincipal);
			details.setTotalInterest(totalInterest);
			details.setTotalPrincipal(totalPrincipal);
		}
		
		for(int j=i; j < mortgageTerm * 12 -1; j++) {
			//remove remaining periods
			MortgagePeriodDetails details = periodList.get(i);
			periodList.remove(details);
		}
	}
}
